using Colorful.Caching;
using Colorful.Furniture.BasicDataManagement;
using Colorful.Furniture.Extensions;
using Colorful.Furniture.PermissionManagement;
using Colorful.Furniture.ReportManagement;
using Colorful.UEditor;
using FastReport.Utils;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.Extensions.Caching.Distributed;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.AntiForgery;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;
using Volo.Abp.VirtualFileSystem;
//using Colorful.Furniture.PaymentManagement.AliPay;

namespace Colorful.Furniture;

[DependsOn(
    typeof(FurnitureHttpApiModule),
    typeof(AbpAutofacModule),
    typeof(FurnitureApplicationModule),
    typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
    typeof(AbpAspNetCoreSerilogModule),
    typeof(AbpSwashbuckleModule),
    typeof(ColorfulCachingModule)
)]
public class FurnitureHttpApiHostModule : AbpModule
{

    public override void PreConfigureServices(ServiceConfigurationContext context)
    {
        PreConfigure<AbpJsonOptions>(options =>
        {
            //使用原生的序列器
            options.UseHybridSerializer = false;
        });

        //redis
        var configuration = context.Services.GetConfiguration();
        var hostingEnvironment = context.Services.GetHostingEnvironment();
        ConfigureCache(configuration);
    }


    private void ConfigureCache(IConfiguration configuration)
    {
        Configure<AbpDistributedCacheOptions>(options =>
        {
            options.KeyPrefix = "CloudMom:";
            //滑动过期
            options.GlobalCacheEntryOptions = new DistributedCacheEntryOptions()
            {
                SlidingExpiration = TimeSpan.FromHours(2)
            };
        });
    }

    /// <summary>
    ///  配置
    /// </summary>
    /// <param name="context"></param>
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var configuration = context.Services.GetConfiguration();
        var hostingEnvironment = context.Services.GetHostingEnvironment();

        //获取懒加载服务驱动
        var sp = context.Services.BuildServiceProvider();
        var lazySp = sp.GetRequiredService<IAbpLazyServiceProvider>();

        //参见：https://learn.microsoft.com/zh-cn/aspnet/core/mvc/models/validation?view=aspnetcore-6.0#non-nullable-reference-types-and-the-required-attribute
        //不可为 null 的引用类型和 [必需] 属性
        context.Services.AddControllers(
            options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);
        //.AddXmlSerializerFormatters()

        if (hostingEnvironment.IsDevelopment())
        {
            //类可以绕过授权服务. 通常用于在需要禁用授权系统的集成测试中.
            //参考：https://docs.abp.io/zh-Hans/abp/latest/Authorization#alwaysallowauthorizationservice
            context.Services.AddAlwaysAllowAuthorization();
        }

        //配置IIS
        Configure<IISServerOptions>(options =>
        {
            options.MaxRequestBodySize = 10737418240;
        });

        //设置表单的最大值
        Configure<FormOptions>(options =>
        {
            options.MultipartBodyLengthLimit = 10737418240;
        });

        Configure<AbpAntiForgeryOptions>(options =>
        {
            options.AutoValidate = false;
        });

        context.Services.Configure<MvcNewtonsoftJsonOptions>(options =>
        {
            options.SerializerSettings.ContractResolver = new PermissionJsonContractResolver(lazySp);

        });



        ConfigureFastReport();
        ConfigureFileUpload(context);
        ConfigureUEditor(context, configuration, hostingEnvironment);
        ConfigureExceptionHandling();
        ConfigureConventionalControllers(context);
        ConfigureAuthentication(context, configuration);
        ConfigureLocalization();
        ConfigureVirtualFileSystem(context);
        ConfigureCors(context, configuration);
        ConfigureSwaggerServices(context, configuration);

        //// 添加支付宝客户端依赖注入
        //// 引入Payment 依赖注入
        //context.Services.AddAlipay();
        ////微信的
        ////services.AddWeChatPay();
        //var t = configuration.GetSection("Alipay");
        //// 在 appsettings.json(开发环境：appsettings.Development.json) 中 配置选项
        //context.Services.Configure<AlipayOptions>(configuration.GetSection("Alipay"));
        ////services.Configure<WeChatPayOptions>(Configuration.GetSection("WeChatPay"))

    }

    /// <summary>
    ///  配置报表
    /// </summary>
    private void ConfigureFastReport()
    {
        RegisteredObjects.AddConnection(typeof(MsSqlDataConnection), "缤纷数据源");
    }

    /// <summary>
    ///  配置百度编辑器
    /// </summary>
    /// <param name="context"></param>
    /// <param name="configuration"></param>
    /// <param name="hostingEnvironment"></param>
    private void ConfigureUEditor(ServiceConfigurationContext context, IConfiguration configuration, IWebHostEnvironment hostingEnvironment)
    {
        //添加百度UEditor编辑器配置
        var uploadFilePath = configuration.GetSection("File:IsUploadWebRoot").Value.ToBool()
            ? hostingEnvironment.WebRootPath
            : configuration.GetSection("File:PhysicalPath").Value;
        context.Services.AddUEditorService("ueditor.json", uploadFilePath);

    }

    /// <summary>
    /// 配置虚拟文件系统
    /// </summary>
    /// <param name="context"></param>
    private void ConfigureVirtualFileSystem(ServiceConfigurationContext context)
    {
        var hostingEnvironment = context.Services.GetHostingEnvironment();

        if (hostingEnvironment.IsDevelopment())
        {
            Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.ReplaceEmbeddedByPhysical<FurnitureDomainSharedModule>(
                    Path.Combine(hostingEnvironment.ContentRootPath,
                        $"..{Path.DirectorySeparatorChar}Colorful.Furniture.Domain.Shared"));
                options.FileSets.ReplaceEmbeddedByPhysical<FurnitureDomainModule>(
                    Path.Combine(hostingEnvironment.ContentRootPath,
                        $"..{Path.DirectorySeparatorChar}Colorful.Furniture.Domain"));
                options.FileSets.ReplaceEmbeddedByPhysical<FurnitureApplicationContractsModule>(
                    Path.Combine(hostingEnvironment.ContentRootPath,
                        $"..{Path.DirectorySeparatorChar}Colorful.Furniture.Application.Contracts"));
                options.FileSets.ReplaceEmbeddedByPhysical<FurnitureApplicationModule>(
                    Path.Combine(hostingEnvironment.ContentRootPath,
                        $"..{Path.DirectorySeparatorChar}Colorful.Furniture.Application"));
            });
        }
    }

    /// <summary>
    ///  配置文件上传
    /// </summary>
    /// <param name="context"></param>
    /// <exception cref="UserFriendlyException"></exception>
    private void ConfigureFileUpload(ServiceConfigurationContext context)
    {
        var configuration = context.Services.GetConfiguration();

        var fileUploadSection = configuration.GetSection("File");
        var aliPaySection = configuration.GetSection("AliPay");

        if (!fileUploadSection.Exists())
            throw new UserFriendlyException("请在appsettings.json中配置File节点");

        Configure<FileConfig>(fileUploadSection);
        //Configure<AliPayConfig>(aliPaySection);
    }

    /// <summary>
    ///  配置动态API
    /// </summary>
    private void ConfigureConventionalControllers(ServiceConfigurationContext context)
    {
        Console.WriteLine(context);

        Configure<AbpAspNetCoreMvcOptions>(options =>
        {
            options.ConventionalControllers.Create(typeof(FurnitureApplicationModule).Assembly);
        });
    }

    /// <summary>
    ///  处理异常
    /// </summary>
    private void ConfigureExceptionHandling()
    {
        Configure<AbpExceptionHandlingOptions>(options =>
        {
            options.SendExceptionsDetailsToClients = false;
        });
    }

    /// <summary>
    ///  配置认证
    /// </summary>
    /// <param name="context"></param>
    /// <param name="configuration"></param>
    private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
    {
        Configure<ColorfulJwtOptions>(configuration.GetSection("Authentication:Jwt"));
        var jwtConfig = configuration.GetSection("Authentication:Jwt").Get<ColorfulJwtOptions>();

        //添加认证
        context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidIssuer = jwtConfig.Issuer,
                    ValidAudience = jwtConfig.Audience,
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.SecurityKey)),
                    // 缓冲过期时间，总的有效时间等于这个时间加上jwt的过期时间，如果不配置，默认是5分钟
                    ClockSkew = TimeSpan.FromSeconds(3)
                };
            });
    }

    /// <summary>
    ///  配置swagger
    /// </summary>
    /// <param name="context"></param>
    /// <param name="configuration"></param>
    private static void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddAbpSwaggerGen(
            options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo { Title = configuration["Swagger:Title"], Description = configuration["Swagger:Description"], Version = "v1" });
                options.DocInclusionPredicate((_, _) => true);
                options.CustomSchemaIds(type => type.FullName);

                //添加安全定义
                options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "Jwt授权Token：Bearer Token",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey,
                    BearerFormat = "JWT",
                    Scheme = "Bearer"
                });

                //添加授权请求
                options.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                        {
                            new OpenApiSecurityScheme
                            {
                                Reference = new OpenApiReference {
                                    Type = ReferenceType.SecurityScheme,
                                    Id = "Bearer"
                                }
                            },
                            new string[] { }
                        }
                });

                //查找运行项目的所有包含.xml文件
                var directoryInfo = new DirectoryInfo(AppContext.BaseDirectory);
                foreach (var item in directoryInfo.GetFiles().Where(x => x.Name.Contains(".xml")))
                {
                    //循环获取.xml文件，包括注释到文件中
                    options.IncludeXmlComments(item.FullName, true);
                }
            })
            .AddSwaggerGenNewtonsoftSupport();
    }

    /// <summary>
    ///  配置语言
    /// </summary>
    private void ConfigureLocalization()
    {
        Configure<AbpLocalizationOptions>(options =>
        {
            options.Languages.Add(new LanguageInfo("en", "en", "English"));
            options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
        });
    }

    /// <summary>
    ///  配置跨域
    /// </summary>
    /// <param name="context"></param>
    /// <param name="configuration"></param>
    private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddCors(options =>
        {
            options.AddDefaultPolicy(builder =>
               {
                   builder
                       .WithOrigins(
                           configuration["App:CorsOrigins"]
                               .Split(",", StringSplitOptions.RemoveEmptyEntries)
                               .Select(o => o.RemovePostFix("/"))
                               .ToArray()
                       )
                       .WithAbpExposedHeaders()
                       .SetIsOriginAllowedToAllowWildcardSubdomains()
                       .AllowAnyHeader()
                       .AllowAnyMethod()
                       .AllowCredentials();
               });
        });
    }

    /// <summary>
    ///  应用程序初始化
    /// </summary>
    /// <param name="context"></param>
    public override void OnApplicationInitialization(ApplicationInitializationContext context)
    {
        var app = context.GetApplicationBuilder();
        var env = context.GetEnvironment();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseAbpRequestLocalization();

        app.UseStaticFiles();

        //配置报表
        app.UseFastReport(options =>
        {
            options.RouteBasePath = "api";
        });

        app.UseRouting();
        app.UseCors();
        app.UseAuthentication();
        app.UseAuthorization();

        app.UseJwtTokenMiddleware();



        //swagger
        var isEnableSwagger = context.GetConfiguration()["Swagger:IsEnabled"];
        if (isEnableSwagger.To<bool>())
        {
            app.UseSwagger();
            app.UseAbpSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "Furniture API");
            });
        }

        app.UseAuditing();
        app.UseAbpSerilogEnrichers();
        app.UseConfiguredEndpoints();
    }
}
